/*

write by wuweiwei
www.github.com/flybirdsoft
www.flybirdsoft.com/WUI

代码功能:
给予SVG技术,实现图片缩放移动,绘图和标注功能

用户操作功能:
1.用户可以画图
2.用户可以标注位置
3.用户可以删除所画图形(右键选中图形,按delete键删除)
4.用户可以删除标注点
5.用户在画图过程中可以按住space键移动画布

*/

var upLoader = {
	upload : function(fileDom,url,callback){
		var th = this;
		th.fileDom = fileDom;
		th.url = url;
		th.callback = callback;

		fileDom.onchange = function(e){
			th._upload(e);
		}
	},
	_upload : function(argument) {
		var th = this;
		var xhr = new XMLHttpRequest(); 
		var fd = new FormData();
		var i , files = this.fileDom.files;
		th.xhr = xhr;
		for(i=0;i<files.length;i++)
		{
			fd.append("file", files[i]);
		}
		//监听事件
		//xhr.upload.addEventListener("progress", uploadProgress, false); 
		//发送文件和表单自定义参数 
		xhr.onreadystatechange = function(e){
			if(th.xhr.readyState==4&&th.xhr.status == 200)
			{
				th.callback.call(th,e);
			}
		}
		xhr.open("POST", this.url,true);
		xhr.send(fd);
	},
	_uploadProgress : function(evt){
		if (evt.lengthComputable) {
			//evt.loaded：文件上传的大小 evt.total：文件总的大
			var percentComplete = Math.round((evt.loaded) * 100 / evt.total);
			//加载进度条，同时显示信息
			$("#percent").html(percentComplete + '%')
			$("#progressNumber").css("width",""+percentComplete+"px");
		}
	}
}


var wGraph = {
	popMenu : null ,/*弹出式菜单dom*/
	menuItems : [
		{
			text : "删除当前元素",
			name : "delete"
		}
	],  /*弹出式菜单项*/
	_pointText : "", /*临时存放标注点的文本信息,通过wGraph.addPoint("xxx")设置*/
	pointConfig : {
		"url" : "images/point.png",
		"width" : 50,
		"height" : 50,
		"color" : "#F00"
	},
	pathConfig : {
		"stroke":"#FFFF00",
		"strokeWidth":"2",
		"fill":"#ffff00"
	},
	selectSvg : null, /*当前选中的svg元素*/
	svgElements : [],  /*存储所有创建的svg元素*/
	svgAttrStr : "",
	svgStartDraw : true,
	svgCurrentIndex : 1,
	svgCounter : {    /*用于创建svg元素命名用*/
		pathCount : 0,
		pointCount : 0
	},

	stateProps : {},       /*存储当前图形的属性,用于恢复当前图形属性*/
	stateStack : [],      /*只有一个元素用于保存当前状态,以便恢复,状态来自mouseOpts*/
	/*存储鼠标操作类型*/
	mouseOpts :{
		"move":"move",
		"path":"path",
		"point":"point"
	},
	mouseOpt : "move",/*存储当前鼠标操作类型*/


	pos : {
		x : 0,
		y : 0,
		isDrag : false,
		scale : 1,
		left : 0,
		top : 0,
		differ : 5
	},
	isZoom : true,    /*是否可以缩放*/
	init : function(options){
		/*
		options = {
			container : dom,
			src : "path/a.jpg",
			isZoom : true|false, 默认true
			isEdit : true|false,  默认true
			pointConfig : pointConfig,
			pathConfig : pathConfig,
			ondblclick : function(){},
			onimageload : function(){},
		}
		*/
		this.options = options;

		this.ondblclick = options.ondblclick;
		this.onimageinit = options.onimageinit;
		this.onimageload = options.onimageload;

		this.options.container.style.position="relative";
		this.options.width = options.width || this.options.container.offsetWidth;
		this.options.height = options.height || this.options.container.offsetHeight;
		
		this.svgHTML = '<svg id="svg" xmlns="http://www.w3.org/2000/svg" class="svg">\
						<g id="svgContainer">\
							<image id="svgImage" x="0" y="0" width="0" height="0" xlink:href="" class="svgImage"/>\
						</g>\
						</svg>';
		this.options.container.innerHTML = (this.svgHTML);
		this.svgDifferX = this.options.container.offsetLeft;
		this.svgDifferY = this.options.container.offsetTop;
		this.isZoom = options.isZoom == undefined ? true : options.isZoom;
		this.isEdit = options.isEdit == undefined ? true : options.isEdit;
		this.pathConfig = options.pathConfig || this.pathConfig;
		this.pointConfig = options.pointConfig || this.pointConfig;

		this.svg = document.getElementById("svg");
		this.svgContainer = document.getElementById("svgContainer");
		this.svgImage = document.getElementById("svgImage");

		this.initPopMenu();
		this.initSize();
		this.loadImage(options.src);
		this.addIcon();
		this.initDrag();
		this.addG();
	},
	/*
	获取G元素的差值
	*/
	get_G_Differ : function(){
		var rect = this.svgContainer.getBoundingClientRect();
		this.rect = rect;
		
		this.G = {};
		this.G.x = rect.x < 0 ? rect.x : rect.x;
		this.G.y = rect.y < 0 ? rect.y : rect.y;
	},
	initSize : function(){
		this.svg.style.width = this.options.width + "px";
		this.svg.style.height = this.options.height + "px";
	},
	loadImage : function(src){
		var th = this;
		var img = new Image();
		this.onimageinit&&this.onimageinit();
		img.onload = function(e){
			th.renderImage(img);
			th.onimageload&&th.onimageload();
		}
		img.src = src;
	},
	renderImage : function(img){
		var wh;
		this.svgImage.setAttribute("xlink:href",img.src);

		if(img.width>=img.height)
		{
			wh = img.width;
		}
		else
		{
			wh = img.height;
		}
		this.svgImage.width.baseVal.value = wh;
		this.svgImage.height.baseVal.value = wh;
		this.get_G_Differ();
	},
	initPopMenu : function(){
		var th = this;
		var menuTpl = '<div class="svgPopItem" name="{name}">{text}</div>',menuhtml,menuHtmls='';
		var i;
		var popMenu = document.createElement("div");
		popMenu.id = "svgPopMenu";
		popMenu.className = "svgPopMenu";
		popMenu.style.position = "absolute";

		for(i=0;i<this.menuItems.length;i++)
		{
			menuhtml = menuTpl.replace("{text}",this.menuItems[i].text).replace("{name}",this.menuItems[i].name);
			menuHtmls += menuhtml;
		}
		popMenu.innerHTML = menuHtmls;
		this.popMenu = popMenu;
		this.options.container.appendChild(popMenu);
		this.popMenu.addEventListener("click",function(e){
			var target = e.target;
			if(target.className=="svgPopItem")
			{
				if(target.getAttribute("name")=="delete")
				{
					th.deleteSvg();
				}
			}
			th.popMenu.style.display = "none";
		},false);
	},
	modifyPopMenu : function(type,options){
		console.log(type,options);
		var th = this;
		var menuTpl = '<div class="svgPopItem" name="{name}">{text}</div>',menuhtml,menuHtmls='';
		var i;
		if(type == "append")
		{
			for(i=0;i<this.menuItems.length;i++)
			{
				menuhtml = menuTpl.replace("{text}",this.menuItems[i].text).replace("{name}",this.menuItems[i].name);
				menuHtmls += menuhtml;
			}			
		}

		for(i=0;i<options.length;i++)
		{
			menuhtml = menuTpl.replace("{text}",options[i].text).replace("{name}",options[i].name);
			menuHtmls += menuhtml;
		}
		this.popMenu.innerHTML = menuHtmls;
	},
	showPopMenu : function(point,type,options){
		/*
		point is position
		type = 'append|cover' is append menu or cover menu
		options is {text:xx,name:xx}
		*/
		this.popMenu.style.display = "block";
		this.popMenu.style.left = point.x + "px";
		this.popMenu.style.top = point.y + "px";
		if(type!=undefined && options!=undefined)
		{
			this.modifyPopMenu(type,options);
		}
	},
	hidePopMenu : function(){
		this.popMenu.style.display = "none";
	},
	initDrag : function(){
		var th = this;
		var cx,cy;
		var transformTpl = "translate({x}px,{y}px) scale({scale})";
		var transform;
		var rect;
		var wheelDelta;
		
		var isIE = function(){
			if(navigator.userAgent.indexOf("Trident")>0)
			{
				return true;
			}
			else
			{
				return false;
			}
		};

		window.onkeydown = function(e){
			if(e.keyCode==46)
			{
				th.deleteSvg();
			}
			else if(e.keyCode==32 && th.mouseOpt == th.mouseOpts.path) /*press space*/
			{
				th.mouseOpt = th.mouseOpts.move;
			}
		}
		window.onkeyup = function(e){
			if(e.keyCode == 32)
			{
				if(th.stateStack.length>0 && th.stateStack[0] == th.mouseOpts.path)
				{
					th.mouseOpt = th.mouseOpts.path;
				}
			}
		}

		/*
		右键主要为了选中元素
		*/
		document.oncontextmenu = window.oncontextmenu = function(e){
			/*用于选中图形或标注点*/
			var target = e.target;
			if(!th.isEdit)
			{
				return;
			}

			if(target.nodeName == "path")
			{
				th.selectSvg = target;
				th.svgG.appendChild(target);
				if(JSON.stringify(th.stateProps[target.id])==undefined)
				{
					th.stateProps[target.id] = {};
					th.stateProps[target.id]["stroke"] = target.getAttribute("stroke");
					th.stateProps[target.id]["fill"] = target.getAttribute("fill");
				}
				target.setAttribute("stroke","#FF0000");
				target.setAttribute("fill","#FF0000");
				th.showPopMenu({
					x : e.pageX - th.svgDifferX,
					y : e.pageY - th.svgDifferY
				});
			}
			else if(target.nodeName == "image" && target.id != "svgImage")
			{
				th.selectSvg = target.parentNode;
				th.showPopMenu({
					x : e.pageX - th.svgDifferX,
					y : e.pageY - th.svgDifferY
				},
				"append",
				[{
					text:"添加数据",
					name:"add"
				}]);
			}

			return false;
		}
		this.svg.ondblclick = function(e){
			th.mouseOpt = th.mouseOpts.move;
			th.drawPathEnd(); /*结束path 绘图*/
			th.ondblclick && th.ondblclick.call(th,e);
		}
		this.svg.onclick = function(e){
			var target = e.target;
			var box,v;
			if(th.mouseOpt!= th.mouseOpts.move)
			{
				return;
			}

			if(target.nodeName=="path")
			{
				th.svgG.appendChild(target);
				for(v in th.stateProps[target.id])
				{
					target.setAttribute(v,th.stateProps[target.id][v]);
				}
				th.stateProps[target.id] = undefined;
			}
			th.hidePopMenu();
		}

		this.svg.onmousedown = function(e){
			var rect;
			th.rect = rect = wGraph.svgContainer.getBoundingClientRect();
			th.rect.x = th.rect.x || th.rect.left;
			th.rect.y = th.rect.y || th.rect.top;

			if(th.mouseOpt == th.mouseOpts.move)
			{
				th.pos.isDrag = true;
				th.pos.x = e.pageX;
				th.pos.y = e.pageY;
				
			}
			else if(th.mouseOpt == th.mouseOpts.path)
			{
				th.drawPath(e,true);
			}
			else if(th.mouseOpt == th.mouseOpts.point)
			{
				th.drawPoint({
					x : e.pageX - th.svgDifferX - th.pos.left,
					y : e.pageY - th.svgDifferY - th.pos.top
				});
				console.log( (e.pageX - th.svgDifferX - th.pos.left)+","+(e.pageY - th.svgDifferY - th.pos.top) );
			}
		}
		this.svg.onmousemove = function(e){
			if(th.mouseOpt == th.mouseOpts.move)
			{
				if(!th.pos.isDrag)
				{
					return;
				}
				cx = e.pageX - th.pos.x;
				cy = e.pageY - th.pos.y;
				transform = transformTpl;
				transform = transform.replace("{x}",th.rect.x + cx - th.svgDifferX).replace("{y}",th.rect.y + cy - th.svgDifferY).replace("{scale}",th.pos.scale);
				th.pos.left = th.rect.x + cx - th.svgDifferX;
				th.pos.top = th.rect.y + cy - th.svgDifferY;
				
				if(isIE())
				{
					th.svgContainer.setAttribute("transform",transform.replace(/px/g,""));
					//th.svgContainer.setAttribute("transform","translate(500, 100) scale(1)");
				}
				else
				{
					th.svgContainer.style.transform = transform;
				}
				
			}
			else if(th.mouseOpt == th.mouseOpts.path)
			{
				if(!th.svgStartDraw)
				{
					th.drawPath(e,false);
				}
			}

		}
		this.svg.onmouseup = function(e){
			th.pos.isDrag = false;
			if(th.mouseOpt == th.mouseOpts.point)
			{
				th.stateStack.pop();
			}
		}

		this.svg.onmousewheel = function(e){
			wheelDelta = e.wheelDelta;
			var differ;
			if(!th.isZoom)
			{
				return;
			}
			if(wheelDelta>0)
			{
				th.pos.scale = th.pos.scale+0.01;
				differ = -th.pos.differ;
			}
			else
			{
				th.pos.scale = th.pos.scale-0.01;
				differ = th.pos.differ;
			}

			if(th.pos.scale<0.3)
			{
				th.pos.scale = 0.3;
				differ = 0;
			}
			if(th.pos.scale>2)
			{
				th.pos.scale = 2;
				differ = 0;
			}

			th.pos.left = th.pos.left + differ;
			th.pos.top = th.pos.top + differ;

			transform = transformTpl;
			transform = transform.replace("{x}",th.pos.left).replace("{y}",th.pos.top).replace("{scale}",th.pos.scale);
			th.svgContainer.style.transform = transform;
		}
	},
	drawPath : function(e,isDraw){
		var svgAttrStr = this.svgAttrStr;
		var temp = " {x} {y}";
		var rect = this.rect;

		if(this.svgStartDraw)
		{
			svgAttrStr = "M {x} {y} L {x} {y}";
			svgAttrStr = svgAttrStr.replace(/\{x\}/g , e.pageX - this.svgDifferX - this.pos.left).replace(/\{y\}/g , e.pageY - this.svgDifferY - this.pos.top);
			this.svgAttrStr = svgAttrStr;
			this.svgStartDraw = false;
		}
		else
		{
			svgAttrStr += temp.replace("{x}", e.pageX - this.svgDifferX - this.pos.left).replace("{y}" , e.pageY - this.svgDifferY - this.pos.top);
			if(isDraw)
			{
				this.svgAttrStr = svgAttrStr;
			}
		}
		this.svgElements[this.svgCurrentIndex].setAttribute("d",svgAttrStr);
	},
	drawPathEnd : function(){
		var svgAttrStr = this.svgAttrStr;
		if(this.svgElements.length!=0)
		{
			this.svgElements[this.svgCurrentIndex].setAttribute("d",svgAttrStr+"Z");
			this.stateStack.pop();
		}
	},

	/*
	外部接口
	功能:删除当前的路径
	*/
	deleteSvg : function(){
		var i;
		var arObj;
		var len;
		var deleteIndex = -1;
		arObj = this.svgElements;
		len = this.svgElements.length;
		for(i=0;i<len;i++)
		{
			if(this.selectSvg == arObj[i])
			{
				deleteIndex = i;
				
				break;
			}
		}
		if(deleteIndex!=-1)
		{
			arObj.splice(deleteIndex,1);
			this.svgG.removeChild(this.selectSvg);
		}
	},
	addG : function(){
		this.svgG = document.createElementNS("http://www.w3.org/2000/svg","g");
		this.svgContainer.appendChild(this.svgG);
	},
	addIcon : function(){
		this.delImage = document.createElementNS("http://www.w3.org/2000/svg","image");
		this.delImage.setAttribute("href","images/delete.png");
		this.delImage.setAttribute("width","30px");
		this.delImage.setAttribute("height","30px");
		this.delImage.style.display = "none";

		this.svgContainer.appendChild(this.delImage);
	},

	/*
	外部接口
	生产path element,开始划线
	*/
	addPath : function(options){
		this.mouseOpt = this.mouseOpts.path;
		this.svgStartDraw = true;
		this.stateStack.push(this.mouseOpts.path); /*存储当前操作状态*/
		var path = document.createElementNS("http://www.w3.org/2000/svg","path");
		path.setAttribute("id","path_"+ ++this.svgCounter.pathCount);
		/*
		g.innerHTML = '<path stroke-linejoin="round" stroke-linecap="round" fill-rule="evenodd" stroke="#FFFF00" \
		stroke-width="2" stroke-dasharray="none" fill="#ffff00" stroke-opacity="0.7" fill-opacity="0.3" \
		style="cursor: pointer; user-select: none;" \
		d="M 196 409 L 290 257 439 187 528 138 582 96 578 33 646 -15 688 11 773 -28 867 6 788 81 928 115 722 297 445 \
		436 368 339 264 445 196 409"></path>';
		*/
		if(options==undefined)
		{
			options = {};
		}
		path.setAttribute("stroke-linejoin","round");
		path.setAttribute("stroke-linecap","round");
		path.setAttribute("fill-rule","evenodd");
		path.setAttribute("stroke",options.stroke || this.pathConfig.stroke);
		path.setAttribute("stroke-width",options.strokeWidth || this.pathConfig.strokeWidth);
		path.setAttribute("stroke-dasharray","none");
		path.setAttribute("fill",options.fill || this.pathConfig.fill);
		path.setAttribute("stroke-opacity","0.7");
		path.setAttribute("fill-opacity","0.3");
		this.svgElements.push(path);
		this.svgG.appendChild(path);
		this.svgCurrentIndex = this.svgElements.length -1;
	},

	/*
	外部接口
	功能:添加位置标注信息
	*/
	addPoint : function(text){
		this.mouseOpt = this.mouseOpts.point;
		this._pointText = text;
	},

	drawPoint : function(point){
		/*
		point = {x,y}
		*/
		this.stateStack.push(this.mouseOpts.point);
		var g = document.createElementNS("http://www.w3.org/2000/svg","g");
		g.setAttribute("class","pointer");
		g.setAttribute("id","point_"+ ++this.svgCounter.pointCount);
		var imagePoint = document.createElementNS("http://www.w3.org/2000/svg","image");
		imagePoint.setAttribute("href",this.pointConfig.url);
		imagePoint.x.baseVal.value = point.x - this.pointConfig.width/2;
		imagePoint.y.baseVal.value = point.y - this.pointConfig.height;
		imagePoint.width.baseVal.value = this.pointConfig.width;
		imagePoint.height.baseVal.value = this.pointConfig.height;
		g.appendChild(imagePoint);
		var text = document.createElementNS("http://www.w3.org/2000/svg","text");
		g.appendChild(text);
		text.setAttribute("fill",this.pointConfig.color);
		text.setAttribute("x",point.x + this.pointConfig.width/3);
		text.setAttribute("y",point.y);
		text.textContent = this._pointText;

		this.svgElements.push(g);
		this.svgG.appendChild(g);
		this.svgCurrentIndex = this.svgElements.length -1;
		this.mouseOpt = this.mouseOpts.move;
	},

	/*
	外部接口
	功能:提供svg path as string
	*/
	getSvgData : function(){
		var i;
		return this.svgG.innerHTML;
	},

	/*
	外部接口
	功能:提供svg path as string
	*/
	setSvgData : function(data){
		/*
		data is string type
		*/
		this.svgG.innerHTML = data;
	},

	/*
	外部接口
	功能:设置样式
	*/
	setPathConfig : function(config){
		var v;
		for(v in config)
		{
			this.pathConfig[v] = config[v];
		}
	},

	/*
	外部接口
	功能:设置样式
	*/
	setPointConfig : function(config){
		var v;
		for(v in config)
		{
			this.pointConfig[v] = config[v];
		}
	}

}











